package afcp.alumni.action.event;

import net.sourceforge.stripes.action.ActionBean;
import net.sourceforge.stripes.action.DefaultHandler;
import net.sourceforge.stripes.action.RedirectResolution;
import net.sourceforge.stripes.action.Resolution;
import net.sourceforge.stripes.action.UrlBinding;
import net.sourceforge.stripes.integration.spring.SpringBean;
import net.sourceforge.stripes.security.SecurityInterceptor;
import net.sourceforge.stripes.security.StripesSecurityFilter;
import net.sourceforge.stripes.validation.LocalizableError;
import net.sourceforge.stripes.validation.Validate;
import net.sourceforge.stripes.validation.ValidationErrors;
import net.sourceforge.stripes.validation.ValidationMethod;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import afcp.alumni.action.base.EventAction;
import afcp.alumni.action.page.HomeAction;
import afcp.alumni.model.db.Member;
import afcp.alumni.security.PasswordEncoder;
import afcp.alumni.service.impl.LoginService;
import afcp.alumni.service.impl.MemberServiceImpl;

@UrlBinding(LoginAction.URL)
public class LoginAction extends EventAction {

	private static final Log logger = LogFactory.getLog(LoginAction.class);

	public static final String URL = "/login";

	@Override
	public String getUrl() {
		return URL;
	}

	@Override
	@DefaultHandler
	public Resolution view() {
		return new RedirectResolution(fromUrl());
	}

	@SpringBean
	private LoginService loginService;
	@SpringBean
	private MemberServiceImpl memberService;
//	@SpringBean
//	private RoleDao roleDao;

	// TODO non géré par les redirections en cas d'erreur. à reporter dans une
	// validation method qui écrit un message ajouté au flash scope
	@Validate(required = true, on = "login", minlength = 2)
	private String loginuser;
	// TODO non géré par les redirections en cas d'erreur. à reporter dans une
	// validation method qui écrit un message ajouté au flash scope
	@Validate(required = true, on = "login", minlength = 2, converter = PasswordEncoder.class)
	private String loginpassword;

	public String getLoginuser() {
		return loginuser;
	}

	public void setLoginuser(String loginuser) {
		this.loginuser = loginuser;
	}

	public String getLoginpassword() {
		return loginpassword;
	}

	public void setLoginpassword(String loginpassword) {
		this.loginpassword = loginpassword;
	}
	
	private Member userLoging = null;
//	private Member getUserLoging() {
//		if (userLoging == null) {
//			userLoging = loginService.findUser(loginuser);
//		}
//		return userLoging;
//	}

	// public String getUser() {
	// return (String) context.getRequest().getSession().getAttribute("user");
	// }

	// TODO utiliser les messages dans flashscope à la place
	@ValidationMethod(on = "login")
	public void validateUser(ValidationErrors errors) {
		try {
//			loginuser.setAncestorKey(roleDao.getEntityAncestor().getKey());
			userLoging = loginService.findUser(loginuser);
			boolean allowed = true;
			if (userLoging == null) {
				boolean isAdmin = MemberServiceImpl.ADMIN_LOGIN.equals(loginuser);
				boolean isTest = MemberServiceImpl.TEST_LOGIN.equals(loginuser);
				if (isAdmin || isTest) {
					logger.info("First connexion. Adding a default administrator"
							+ " and test member to the datastore and continuing login "
							+ "process...");
					userLoging = memberService.initDefaultMembers(isAdmin);
				}
			}
			if (userLoging == null) {
				errors.addGlobalError(new LocalizableError("database.dontexist"));
				allowed = false;
			} else if (userLoging.getPassword() == null) {
				errors.addGlobalError(new LocalizableError(
						"database.passwordnotgen"));
				allowed = false;
			} else if (!loginpassword.equals(userLoging.getPassword())) {
				errors.addGlobalError(new LocalizableError(
						"database.incorrectpassword"));
				allowed = false;
			}
			if (allowed) {
				logger.info("User " + userLoging.getFirstName() + " "
						+ userLoging.getLastName() + " (" + loginuser
						+ ") is allowed to login.");
			} else {
				logger.info("User "
						+ loginuser
						+ " is not allowed to login. unknown account or incorrect password.");
			}
		} catch (Exception e) {
			logger.error("An error occurred during user validation.", e);
			errors.addGlobalError(new LocalizableError("auth.unknownerror"));
			// TODO faire mieux pour les erreurs. Elles ne remontent pas en cas de redirection.
		}
	}
	
	public Resolution login() {
		loginService.login(userLoging, context);
//		Resolution sourcePage = this.context.getSourcePageResolution();
		return fromRedirect();
	}

	public Resolution logout() {
		loginService.logout(context);
		
		// Tente d'identifier la page sur laquelle on se trouve en utilisant l'URL
		// de la page actuelle, insérée dans le formulaire de déconnexion.
		if (from != null) {
			Class<? extends ActionBean> clazz = StripesSecurityFilter
					.getConfiguration().getActionResolver()
					.getActionBeanType(from);
			// Si la page actuelle n'est pas sécurisée, on y reste.
			if (clazz != null
					&& SecurityInterceptor.getSecureAnnotationFromClass(clazz) == null) {
				return new RedirectResolution(clazz);
			}
		}
		
		return new RedirectResolution(HomeAction.class);
	}
	
	private String from = null;
	
	public void setFrom(String from) {
		this.from = from;
	}

	private String fromUrl = null;
	@Override
	protected String fromUrl() {
		if (fromUrl == null) {
			if (from != null) {
				logger.info("Redirecting to source page: " + from);
				fromUrl = from;
			} else {
				logger.warn("The source page where the request come from has not been found. Can't redirect to the page where the user was when sending the login request.");
				fromUrl = HomeAction.URL;
			}
		}
		return fromUrl;
	}
}
